From 11592cdfeaa33428d290e2e8a9016b6486e2a7a7 Mon Sep 17 00:00:00 2001 From: tsteven4 <13596209+tsteven4@users.noreply.github.com> Date: Sat, 18 Nov 2023 18:18:04 -0700 Subject: [PATCH] convert ozi to Format class. (#1232) * convert ozi to Format class. There is a subtle difference in the writer, the index is now reset for every invocation. This only matters if the writer is used more than once. I believe this was the intent. * fool with QIODevice and it's inheritence of QIODeviceBase. --- CMakeLists.txt | 1 + ozi.cc | 248 ++++++++++++++++--------------------------------- ozi.h | 198 +++++++++++++++++++++++++++++++++++++++ vecs.cc | 4 +- 4 files changed, 280 insertions(+), 171 deletions(-) create mode 100644 ozi.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 3308221d2..1c01b45d9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -233,6 +233,7 @@ set(HEADERS mkshort.h nmea.h osm.h + ozi.h qstarz_bl_1000.h random.h session.h diff --git a/ozi.cc b/ozi.cc index 74e33262a..d1ab73aa9 100644 --- a/ozi.cc +++ b/ozi.cc @@ -36,6 +36,8 @@ */ +#include "ozi.h" + #include // for tolower #include // for lround @@ -43,18 +45,20 @@ #include // for operator==, QChar #include // for QFile #include // for QFileInfo -#include // for operator|, QIODevice::WriteOnly, QIODevice::ReadOnly, QIODevice, QIODevice::OpenModeFlag -#include // for QString +#include // for QFlags +#include // for operator&, QIODevice +#include // for QList, QList<>::const_iterator +#include // for QString, operator== #include // for QStringList +#include // for qMakeStringPrivate, QStringLiteral #include // for QTextStream, operator<<, qSetRealNumberPrecision, QTextStream::FixedNotation -#include // for QVector #include // for CaseInsensitive #include // for qPrintable #include "defs.h" #include "csv_util.h" // for csv_stringclean -#include "formspec.h" // for FsChainAdd, FsChainFind, kFsOzi, FormatSpecificData -#include "jeeps/gpsmath.h" // for GPS_Math_Known_Datum_To_WGS84_M +#include "formspec.h" // for FormatSpecificDataList, kFsOzi +#include "jeeps/gpsmath.h" // for GPS_Lookup_Datum_Index, GPS_Math_Known_Datum_To_WGS84_M #include "mkshort.h" // for MakeShort #include "src/core/datetime.h" // for DateTime #include "src/core/textstream.h" // for TextStream @@ -64,101 +68,8 @@ #define BADCHARS ",\r\n" #define DAYS_SINCE_1990 25569 -struct ozi_fsdata : FormatSpecificData { - ozi_fsdata() : FormatSpecificData(kFsOzi) {} - - ozi_fsdata* clone() const override - { - return new ozi_fsdata(*this); - } - - int fgcolor{0}; - int bgcolor{65535}; -}; - -static gpsbabel::TextStream* stream = nullptr; - -static MakeShort* mkshort_handle; -static route_head* trk_head; -static route_head* rte_head; - -static int track_out_count; -static int route_out_count; -static int route_wpt_count; -static int new_track; - -static char* snlenopt = nullptr; -static char* snwhiteopt = nullptr; -static char* snupperopt = nullptr; -static char* snuniqueopt = nullptr; -static char* wptfgcolor = nullptr; -static char* wptbgcolor = nullptr; -static char* pack_opt = nullptr; -static int datum; -static char* proximityarg = nullptr; -static double proximity; -static char* altunit_opt; -static char* proxunit_opt; -static char altunit; -static char proxunit; -static double alt_scale; -static double prox_scale; -static char* opt_codec; - -static -QVector ozi_args = { - { - "pack", &pack_opt, "Write all tracks into one file", - nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr - }, - { - "snlen", &snlenopt, "Max synthesized shortname length", - "32", ARGTYPE_INT, "1", nullptr, nullptr - }, - { - "snwhite", &snwhiteopt, "Allow whitespace synth. shortnames", - nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr - }, - { - "snupper", &snupperopt, "UPPERCASE synth. shortnames", - nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr - }, - { - "snunique", &snuniqueopt, "Make synth. shortnames unique", - nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr - }, - { - "wptfgcolor", &wptfgcolor, "Waypoint foreground color", - "black", ARGTYPE_STRING, ARG_NOMINMAX, nullptr - }, - { - "wptbgcolor", &wptbgcolor, "Waypoint background color", - "yellow", ARGTYPE_STRING, ARG_NOMINMAX, nullptr - }, - { - "proximity", &proximityarg, "Proximity distance", - "0", ARGTYPE_STRING, ARG_NOMINMAX, nullptr - }, - { - "altunit", &altunit_opt, "Unit used in altitude values", - "feet", ARGTYPE_STRING, ARG_NOMINMAX, nullptr - }, - { - "proxunit", &proxunit_opt, "Unit used in proximity values", - "miles", ARGTYPE_STRING, ARG_NOMINMAX, nullptr - }, - { - "codec", &opt_codec, "codec to use for reading and writing strings (default windows-1252)", - "windows-1252", ARGTYPE_STRING, ARG_NOMINMAX, nullptr - }, -}; - -static gpsdata_type ozi_objective; - -static QString ozi_ofname; - -static void -ozi_open_io(const QString& fname, QIODevice::OpenModeFlag mode) +void +OziFormat::ozi_open_io(const QString& fname, QIODevice::OpenModeFlag mode) { stream = new gpsbabel::TextStream; stream->open(fname, mode, MYNAME, opt_codec); @@ -168,8 +79,8 @@ ozi_open_io(const QString& fname, QIODevice::OpenModeFlag mode) } } -static void -ozi_close_io() +void +OziFormat::ozi_close_io() { if (!stream) { return; @@ -179,9 +90,8 @@ ozi_close_io() stream = nullptr; } -static -ozi_fsdata* -ozi_alloc_fsdata() +OziFormat::ozi_fsdata* +OziFormat::ozi_alloc_fsdata() { auto* fsdata = new ozi_fsdata; @@ -192,8 +102,8 @@ ozi_alloc_fsdata() return fsdata; } -static QString -ozi_get_time_str(const Waypoint* waypointp) +QString +OziFormat::ozi_get_time_str(const Waypoint* waypointp) { if (waypointp->creation_time.isValid()) { double time = (waypt_time(waypointp) / SECONDS_PER_DAY) + DAYS_SINCE_1990; @@ -202,8 +112,8 @@ ozi_get_time_str(const Waypoint* waypointp) return QString(""); } -static void -ozi_set_time_str(const QString& str, Waypoint* waypointp) +void +OziFormat::ozi_set_time_str(const QString& str, Waypoint* waypointp) { double ozi_time = str.toDouble(); @@ -213,8 +123,8 @@ ozi_set_time_str(const QString& str, Waypoint* waypointp) } } -static void -ozi_convert_datum(Waypoint* wpt) +void +OziFormat::ozi_convert_datum(Waypoint* wpt) const { if (datum != kDautmWGS84) { double lat, lon, alt; @@ -225,8 +135,8 @@ ozi_convert_datum(Waypoint* wpt) } } -static void -ozi_openfile(const QString& fname) +void +OziFormat::ozi_openfile(const QString& fname) { const char* ozi_extensions[] = {nullptr, "plt", "wpt", "rte"}; @@ -266,8 +176,8 @@ ozi_openfile(const QString& fname) ozi_open_io(tmpname, QFile::WriteOnly); } -static void -ozi_track_hdr(const route_head* rte) +void +OziFormat::ozi_track_hdr(const route_head* rte) { if ((! pack_opt) || (track_out_count == 0)) { ozi_openfile(ozi_ofname); @@ -285,8 +195,8 @@ ozi_track_hdr(const route_head* rte) new_track = 1; } -static void -ozi_track_disp(const Waypoint* waypointp) +void +OziFormat::ozi_track_disp(const Waypoint* waypointp) { double alt; @@ -307,14 +217,20 @@ ozi_track_disp(const Waypoint* waypointp) new_track = 0; } -static void -ozi_track_pr() +void +OziFormat::ozi_track_pr() { - track_disp_all(ozi_track_hdr, nullptr, ozi_track_disp); + auto ozi_track_hdr_lambda = [this](const route_head* rte)->void { + ozi_track_hdr(rte); + }; + auto ozi_track_disp_lambda = [this](const Waypoint* waypointp)->void { + ozi_track_disp(waypointp); + }; + track_disp_all(ozi_track_hdr_lambda, nullptr, ozi_track_disp_lambda); } -static void -ozi_route_hdr(const route_head* rte) +void +OziFormat::ozi_route_hdr(const route_head* rte) { /* prologue on 1st pass only */ if (route_out_count == 0) { @@ -344,8 +260,8 @@ ozi_route_hdr(const route_head* rte) << rte->rte_desc << ",\r\n"; } -static void -ozi_route_disp(const Waypoint* waypointp) +void +OziFormat::ozi_route_disp(const Waypoint* waypointp) { route_wpt_count++; @@ -390,14 +306,20 @@ ozi_route_disp(const Waypoint* waypointp) } -static void -ozi_route_pr() +void +OziFormat::ozi_route_pr() { - route_disp_all(ozi_route_hdr, nullptr, ozi_route_disp); + auto ozi_route_hdr_lambda = [this](const route_head* rte)->void { + ozi_route_hdr(rte); + }; + auto ozi_route_disp_lambda = [this](const Waypoint* waypointp)->void { + ozi_route_disp(waypointp); + }; + route_disp_all(ozi_route_hdr_lambda, nullptr, ozi_route_disp_lambda); } -static void -ozi_init_units(const int direction) /* 0 = in; 1 = out */ +void +OziFormat::ozi_init_units(const int direction) /* 0 = in; 1 = out */ { altunit = tolower(*altunit_opt); switch (altunit) { @@ -433,22 +355,22 @@ ozi_init_units(const int direction) /* 0 = in; 1 = out */ } } -static void -rd_init(const QString& fname) +void +OziFormat::rd_init(const QString& fname) { ozi_open_io(fname, QFile::ReadOnly); ozi_init_units(0); } -static void -rd_deinit() +void +OziFormat::rd_deinit() { ozi_close_io(); } -static void -wr_init(const QString& fname) +void +OziFormat::wr_init(const QString& fname) { /* At this point, we have no idea whether we'll be writing waypoint, @@ -484,8 +406,8 @@ wr_init(const QString& fname) parse_distance(proximityarg, &proximity, 1 / prox_scale, MYNAME); } -static void -wr_deinit() +void +OziFormat::wr_deinit() { ozi_close_io(); ozi_ofname.clear(); @@ -494,8 +416,8 @@ wr_deinit() mkshort_handle = nullptr; } -static void -ozi_parse_waypt(int field, const QString& str, Waypoint* wpt_tmp, ozi_fsdata* fsdata) +void +OziFormat::ozi_parse_waypt(int field, const QString& str, Waypoint* wpt_tmp, ozi_fsdata* fsdata) const { double alt; @@ -589,8 +511,8 @@ ozi_parse_waypt(int field, const QString& str, Waypoint* wpt_tmp, ozi_fsdata* fs } } -static void -ozi_parse_track(int field, const QString& str, Waypoint* wpt_tmp, char* trk_name) +void +OziFormat::ozi_parse_track(int field, const QString& str, Waypoint* wpt_tmp, char* trk_name) { if (str.isEmpty()) { return; @@ -634,8 +556,8 @@ ozi_parse_track(int field, const QString& str, Waypoint* wpt_tmp, char* trk_name } } -static void -ozi_parse_routepoint(int field, const QString& str, Waypoint* wpt_tmp) +void +OziFormat::ozi_parse_routepoint(int field, const QString& str, Waypoint* wpt_tmp) { if (str.isEmpty()) { return; @@ -694,8 +616,8 @@ ozi_parse_routepoint(int field, const QString& str, Waypoint* wpt_tmp) } } -static void -ozi_parse_routeheader(int field, const QString& str) +void +OziFormat::ozi_parse_routeheader(int field, const QString& str) { switch (field) { @@ -724,8 +646,8 @@ ozi_parse_routeheader(int field, const QString& str) } } -static void -data_read() +void +OziFormat::read() { QString buff; char* trk_name = nullptr; @@ -853,10 +775,9 @@ data_read() } } -static void -ozi_waypt_pr(const Waypoint* wpt) +void +OziFormat::ozi_waypt_pr(const Waypoint* wpt, int index) { - static int index = 0; double alt; QString description; QString shortname; @@ -901,8 +822,6 @@ ozi_waypt_pr(const Waypoint* wpt) description = csv_stringclean(wpt->description, BADCHARS); } - index++; - if (wpt->icon_descr.toInt()) { icon = wpt->icon_descr.toInt(); } @@ -931,8 +850,8 @@ ozi_waypt_pr(const Waypoint* wpt) } } -static void -data_write() +void +OziFormat::write() { if (waypt_count()) { track_out_count = route_out_count = 0; @@ -942,7 +861,12 @@ data_write() << "WGS 84\r\n" << "Reserved 2\r\n" << "Reserved 3\r\n"; - waypt_disp_all(ozi_waypt_pr); + + int index = 0; + auto ozi_waypt_pr_lambda = [this, &index](const Waypoint* waypointp)->void { + ozi_waypt_pr(waypointp, ++index); + }; + waypt_disp_all(ozi_waypt_pr_lambda); } if (track_count()) { @@ -957,17 +881,3 @@ data_write() } } - -ff_vecs_t ozi_vecs = { - ff_type_file, - FF_CAP_RW_ALL, - rd_init, - wr_init, - rd_deinit, - wr_deinit, - data_read, - data_write, - nullptr, - &ozi_args, - NULL_POS_OPS -}; diff --git a/ozi.h b/ozi.h new file mode 100644 index 000000000..bcb8a4062 --- /dev/null +++ b/ozi.h @@ -0,0 +1,198 @@ +/* + OziExplorer Waypoints/Tracks/Routes + Comma Delimited + + As described in OziExplorer Help File + + Copyright (C) 2002-2005 Robert Lipe, robertlipe+source@gpsbabel.org + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + Reference: + https://www.oziexplorer4.com/eng/help/fileformats.html + + According to the OZI Explorer developer: + "There is no specified character set, it defaults to whatever 8 bit + character set "Windows" defaults to - normally CP-1252 but can vary + depending on Windows regional settings." + + According to the reference, for some text fields: + "comma's not allowed in text fields, character 209 can be used instead + and a comma will be substituted." + This could work for windows-1252, but not for utf-8. + We don't support any special handling for character 209. + + */ +#ifndef OZI_H_INCLUDED_ +#define OZI_H_INCLUDED_ + +#include // for QIODeviceBase, QIODeviceBase::OpenModeFlag +#include // for QString +#include // for QVector + +#include "defs.h" +#include "format.h" // for Format +#include "formspec.h" // for FormatSpecificData, kFsOzi +#include "mkshort.h" // for MakeShort +#include "src/core/textstream.h" // for TextStream + + +class OziFormat : public Format +{ +public: + QVector* get_args() override + { + return &ozi_args; + } + + ff_type get_type() const override + { + return ff_type_file; + } + + QVector get_cap() const override + { + return FF_CAP_RW_ALL; + } + + void rd_init(const QString& fname) override; + void read() override; + void rd_deinit() override; + void wr_init(const QString& fname) override; + void write() override; + void wr_deinit() override; + +private: + /* Types */ + + struct ozi_fsdata : FormatSpecificData { + ozi_fsdata() : FormatSpecificData(kFsOzi) {} + + ozi_fsdata* clone() const override + { + return new ozi_fsdata(*this); + } + + int fgcolor{0}; + int bgcolor{65535}; + }; + + /* Member Functions */ + + void ozi_open_io(const QString& fname, QIODevice::OpenModeFlag mode); + void ozi_close_io(); + ozi_fsdata* ozi_alloc_fsdata(); + static QString ozi_get_time_str(const Waypoint* waypointp); + static void ozi_set_time_str(const QString& str, Waypoint* waypointp); + void ozi_convert_datum(Waypoint* wpt) const; + void ozi_openfile(const QString& fname); + void ozi_track_hdr(const route_head* rte); + void ozi_track_disp(const Waypoint* waypointp); + void ozi_track_pr(); + void ozi_route_hdr(const route_head* rte); + void ozi_route_disp(const Waypoint* waypointp); + void ozi_route_pr(); + void ozi_init_units(int direction); + void ozi_parse_waypt(int field, const QString& str, Waypoint* wpt_tmp, ozi_fsdata* fsdata) const; + void ozi_parse_track(int field, const QString& str, Waypoint* wpt_tmp, char* trk_name); + static void ozi_parse_routepoint(int field, const QString& str, Waypoint* wpt_tmp); + void ozi_parse_routeheader(int field, const QString& str); + void data_read(); + void ozi_waypt_pr(const Waypoint* wpt, int index); + void data_write(); + + /* Data Members */ + + gpsbabel::TextStream* stream = nullptr; + + MakeShort* mkshort_handle{}; + route_head* trk_head{}; + route_head* rte_head{}; + + int track_out_count{}; + int route_out_count{}; + int route_wpt_count{}; + int new_track{}; + + char* snlenopt = nullptr; + char* snwhiteopt = nullptr; + char* snupperopt = nullptr; + char* snuniqueopt = nullptr; + char* wptfgcolor = nullptr; + char* wptbgcolor = nullptr; + char* pack_opt = nullptr; + int datum{}; + char* proximityarg = nullptr; + double proximity{}; + char* altunit_opt{}; + char* proxunit_opt{}; + char altunit{}; + char proxunit{}; + double alt_scale{}; + double prox_scale{}; + char* opt_codec{}; + + QVector ozi_args = { + { + "pack", &pack_opt, "Write all tracks into one file", + nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr + }, + { + "snlen", &snlenopt, "Max synthesized shortname length", + "32", ARGTYPE_INT, "1", nullptr, nullptr + }, + { + "snwhite", &snwhiteopt, "Allow whitespace synth. shortnames", + nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr + }, + { + "snupper", &snupperopt, "UPPERCASE synth. shortnames", + nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr + }, + { + "snunique", &snuniqueopt, "Make synth. shortnames unique", + nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr + }, + { + "wptfgcolor", &wptfgcolor, "Waypoint foreground color", + "black", ARGTYPE_STRING, ARG_NOMINMAX, nullptr + }, + { + "wptbgcolor", &wptbgcolor, "Waypoint background color", + "yellow", ARGTYPE_STRING, ARG_NOMINMAX, nullptr + }, + { + "proximity", &proximityarg, "Proximity distance", + "0", ARGTYPE_STRING, ARG_NOMINMAX, nullptr + }, + { + "altunit", &altunit_opt, "Unit used in altitude values", + "feet", ARGTYPE_STRING, ARG_NOMINMAX, nullptr + }, + { + "proxunit", &proxunit_opt, "Unit used in proximity values", + "miles", ARGTYPE_STRING, ARG_NOMINMAX, nullptr + }, + { + "codec", &opt_codec, "codec to use for reading and writing strings (default windows-1252)", + "windows-1252", ARGTYPE_STRING, ARG_NOMINMAX, nullptr + }, + }; + + gpsdata_type ozi_objective{unknown_gpsdata}; + + QString ozi_ofname; +}; +#endif // OZI_H_INCLUDED_ diff --git a/vecs.cc b/vecs.cc index 0db4b44ad..eb198a7f5 100644 --- a/vecs.cc +++ b/vecs.cc @@ -65,6 +65,7 @@ #include "lowranceusr.h" // for LowranceusrFormat #include "nmea.h" // for NmeaFormat #include "osm.h" // for OsmFormat +#include "ozi.h" // for OziFormat #include "qstarz_bl_1000.h" // for QstarzBL1000Format #include "random.h" // for RandomFormat #include "shape.h" // for ShapeFormat @@ -82,7 +83,6 @@ extern ff_vecs_t geo_vecs; -extern ff_vecs_t ozi_vecs; #if MAXIMAL_ENABLED extern ff_vecs_t mtk_vecs; extern ff_vecs_t mtk_fvecs; @@ -111,7 +111,7 @@ struct Vecs::Impl { GarminFormat garmin_fmt; GdbFormat gdb_fmt; NmeaFormat nmea_fmt; - LegacyFormat ozi_fmt {ozi_vecs}; + OziFormat ozi_fmt; KmlFormat kml_fmt; #if MAXIMAL_ENABLED LowranceusrFormat lowranceusr_fmt; -- 2.30.2